import re
import time
import json
import base64
import hashlib
import requests
from lxml import etree
from zlib import decompress
from units import removeEmoji

class DanmakuItem(object):
    def __init__(self, timeOffset, content, color='16777215'):
        self.timeOffset = "{:.5f}".format(timeOffset)
        self.content = content.replace('\n', ' ')
        self.color = color

def handleDanmu(params):
    if 'fontSize' in params:
        fontSize = int(params['fontSize'])
        if fontSize > 25:
            fontSize = 36
        elif fontSize < 25:
            fontSize = 18
        else:
            fontSize =25
    else:
        fontSize = 25
    contents = """<i>
<chatserver>YingShi</chatserver>
<chatid>0000000</chatid>
<mission>0</mission>
<maxlimit>500</maxlimit>
<state>0</state>
<real_name>0</real_name>
<source>k-v</source>\n"""
    try:
        if params['platform'] == 'bilibili':
            header['Referer'] = "https://www.bilibili.com"
            r = requests.get(params['url'], headers=header, timeout=5)
            oid = re.search(r'\"cid\":(.*?),', r.text).group(1)
            url = f'https://api.bilibili.com/x/v1/dm/list.so?oid={oid}'
            r = requests.get(url, headers=header, timeout=5)
            contents = r.content.decode()
            return contents, False
        url = 'https://dmku.m3u8.pw/dm.php?url=' + params['url']
        r = requests.get(url, headers=header, timeout=15)
        items = r.json()['danmuku'][2:]
        if len(items) == 0:
            return params, True
        for item in items:
            color = item[2] if not item[2] == '#fff' else '#ffffff'
            content = removeEmoji(item[4], True)
            if len(content) == 0:
                continue
            contents += ' <d p="{:.5f},1,{},{}">{}</d>\n'.format(item[0], fontSize, str(int(color.strip('#'), 16)), content)
        return contents + "</i>", False
    except:
        return params, True

def handleStream(params):
    if 'fontSize' in params:
        fontSize = int(params['fontSize'])
        if fontSize > 25:
            fontSize = 36
        elif fontSize < 25:
            fontSize = 18
        else:
            fontSize =25
    else:
        fontSize = 25
    yield """<i>
<chatserver>YingShi</chatserver>
<chatid>0000000</chatid>
<mission>0</mission>
<maxlimit>500</maxlimit>
<state>0</state>
<real_name>0</real_name>
<source>k-v</source>"""
    maxRow = 10
    rowToNext = [0 for _ in range(maxRow)]
    items = getDanmukuItems(params)
    for item in items:
        item.content = removeEmoji(item.content, True)
        if len(item.content) == 0:
            continue
        start = float(item.timeOffset)
        for row in range(maxRow):
            if start >= rowToNext[row]:
                rowToNext[row] = int(start + len(item.content) * 0.25 + 2.5)
                yield ' <d p="{},1,{},{}">{}</d>'.format(item.timeOffset, fontSize, item.color, item.content)
                break
    yield "</i>"

def getDanmukuItems(params):
    url = params['url']
    platform = params['platform']
    if platform == 'qq':
        return getQqItems(url)
    elif platform == 'mgtv':
        return getMgtvItems(url)
    elif platform == 'iqiyi':
        return getIqiyiItems(url)
    elif platform == 'youku':
        return getYoukuItems(url)
    else:
        return ''

def getQqItems(url):
    r = requests.get(url, headers=header, verify=False, timeout=15)
    try:
        data = json.loads(re.search(r'"videoInfo":({.*?}),\"playInfoFetched\"', r.content.decode()).group(1))
        videoDuration = int(data['duration'])
        vid = data['vid']
    except:
        videoDuration = 0
        vid = re.search(r'http.*/(.*?)\.html', url).group(1)
    for i in range(0, videoDuration * 1000, 30000):
        if i > videoDuration * 1000:
            break
        url = 'https://dm.video.qq.com/barrage/segment/{}/t/v1/{}/{}'.format(vid, i, i + 30000)
        r = requests.get(url, headers=header, verify=False, timeout=15)
        if r.status_code != 200:
            break
        for item in r.json()['barrage_list']:
            try:
                if item['content_style'] != '':
                    color = str(int((int(json.loads(item['content_style'])['gradient_colors'][0], 16) + int(json.loads(item['content_style'])['gradient_colors'][1], 16))/2))
                else:
                    color = '16777215'
            except:
                color = '16777215'
            yield DanmakuItem(int(item['time_offset'])/1000, item['content'], color)

def getMgtvItems(url):
    m = re.search(r'://www.mgtv.com/b/(\d+)/(\d+).html', url)
    cid = m.group(1)
    vid = m.group(2)
    r = requests.get(url, headers=header, verify=False, timeout=15)
    try:
        duration = re.search(r'}}}}\(.*?(\d+:\d+:\d+|\d+:\d+).*?,void', r.text).group(1)
        videoDuration = durationToSeconds(duration)
    except:
        videoDuration = 0
    vtime = 0
    while vtime <= videoDuration * 1000:
        params = {
            'cid': cid,
            'vid': vid,
            'time': vtime,
            'allowedRC': '1'
        }
        r = requests.get('https://galaxy.bz.mgtv.com/cdn/opbarrage', params=params, headers=header, verify=False, timeout=15)
        if r.status_code != 200:
            break
        data = r.json()
        if data['status'] != 0:
            break
        items = data['data']['items']
        if items:
            itemList = sorted(data['data']['items'], key=lambda x: x['time'])
            for item in itemList:
                try:
                    if 'v2_color' in item:
                        color = str(int(((item['v2_color']['color_left']['r'] << 16) + (item['v2_color']['color_left']['g'] << 8) + item['v2_color']['color_left']['b'] + (item['v2_color']['color_left']['r'] << 16) + (item['v2_color']['color_right']['g'] << 8) + item['v2_color']['color_left']['b'])/2))
                    else:
                        color = '16777215'
                except:
                    color = '16777215'
                yield DanmakuItem(int(item['time'])/1000, item['content'], color)
        vtime = data['data']['next']

def getIqiyiItems(url):
    r = requests.get(url, headers=header, verify=False, timeout=15)
    try:
        data = json.loads(re.search(r'playPageInfo=(.*?);', r.text).group(1))
        tvid = str(data['tvId'])
        videoDuration = durationToSeconds(data['duration'])
    except:
        tvid = re.search(r"\"tvId\":(\d+),", r.text).group(1)
        videoDuration = 0
    for i in range(1, int(videoDuration / 300 + 2), 1):
        url = 'https://cmts.iqiyi.com/bullet/{}/{}/{}_300_{}.z'.format(tvid[-4:-2], tvid[-2:], tvid, i)
        r = requests.get(url, headers=header, verify=False, timeout=15)
        try:
            data = decompress(r.content)
            soup = etree.fromstring(data)
            items = soup.xpath('//bulletInfo')
        except:
            items = []
        for item in items:
            try:
                color = int(item.xpath('./color/text()')[0], 16)
            except:
                color = '16777215'
            vtime = int(item.xpath('./showTime/text()')[0])
            content = item.xpath('./content/text()')[0]
            yield DanmakuItem(vtime, content, color)

def getYoukuItems(url):
    s = requests.Session()
    vid = re.search(r'://v.youku.com/v_show/id_([\w=]+).html', url).group(1)
    app_key = '24679788'
    guid = 'NJnMGnrls3wCAXQaiNsMGIsY'
    r = s.get('https://acs.youku.com/h5/mtop.youku.favorite.query.isfavorite/1.0/', params={'appKey': app_key}, headers=header, verify=False, timeout=15)
    token = re.search(r'_m_h5_tk=(\w+)_', r.headers['Set-Cookie']).group(1)
    emptyMats = 0
    for mat in range(120):
        t = int(time.time()) * 1000
        msg = base64.b64encode(json.dumps({"ctime": t, "ctype": 10004, "cver": "v1.0", "guid": guid, "mat": mat, "mcount": 1, "pid": 0, "sver": "3.1.0", "vid": vid}).encode()).decode()
        data = {'pid': 0, 'ctype': 10004, 'sver': '3.1.0', 'cver': 'v1.0', 'ctime': t, 'guid': guid, 'vid': vid, "mat": mat, "mcount": 1, "type": 1, 'msg': msg}
        data['sign'] = hashlib.md5((msg + 'MkmC9SoIw6xCkSKHhJ7b5D2r51kBiREr').encode()).hexdigest()
        data = json.dumps(data)
        params = {'jsv': '2.7.0', 'appKey': app_key, 't': t, 'api': 'mopen.youku.danmu.list', 'v': '1.0', 'type': 'originaljson', 'dataType': 'jsonp', 'timeout': 20000, 'jsonpIncPrefix': 'utility'}
        params['sign'] = hashlib.md5('{}&{}&{}&{}'.format(token, t, app_key, data).encode()).hexdigest()
        r = s.post('https://acs.youku.com/h5/mopen.youku.danmu.list/1.0/', data={'data': data}, params=params, headers=header, verify=False, timeout=15)
        result = json.loads(r.json()['data']['result'])
        if result['code'] != 1:
            break
        items = sorted(result['data']['result'], key=lambda x: x['playat'])
        if len(items) == 0:
            emptyMats += 1
            if emptyMats >= 5:
                break
            continue
        else:
            emptyMats = 0
        for item in items:
            try:
                colorInfos = json.loads(item['propertis'])
                if 'gradientColors' in colorInfos:
                    color = str(int((colorInfos['gradientColors'][0] + colorInfos['gradientColors'][1])/2))
                else:
                    color = '16777215'
            except:
                color = '16777215'
            yield DanmakuItem(item['playat']/1000, item['content'], color)

def durationToSeconds(duration: str) -> int:
    timeParts = duration.split(":")
    timeParts.reverse()
    seconds = 0
    for i, part in enumerate(timeParts):
        seconds += int(part) * (60 ** i)
    return seconds

header = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.54 Safari/537.36"
    }
